// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------

package raft

import (
	"bytes"
	"encoding/binary"
	"io"
	"os"

	"github.com/pkg/errors"
)

const defaultDirPermission = 0755

func copyFile(old io.ReadCloser, newFileName string) error {
	newFile, err := os.OpenFile(newFileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	defer newFile.Close()
	_, err = io.Copy(newFile, old)
	if err != nil {
		return err
	}
	return nil
}

func ensureDir(dirName string) error {
	info, err := os.Stat(dirName)
	if !os.IsNotExist(err) && !info.Mode().IsDir() {
		return errors.New("file already existed")
	}

	err = os.Mkdir(dirName, defaultDirPermission)
	if err == nil || os.IsExist(err) {
		return nil
	}
	return err
}

func makeRaftLogCommand(t CommandType, content KVCommand) ([]byte, error) {
	buf := bytes.NewBuffer(nil)
	buf.WriteByte(uint8(t))
	c := make([]byte, 8)
	binary.LittleEndian.PutUint64(c, uint64(content.Key))
	buf.Write(c)
	binary.LittleEndian.PutUint64(c, uint64(content.Value))
	buf.Write(c)
	return buf.Bytes(), nil
}

func unmarshalRaftLog(in []byte) (CommandType, KVCommand) {
	cmd := CommandType(in[0])
	key := int64(binary.LittleEndian.Uint64(in[1 : 1+8]))
	value := int64(binary.LittleEndian.Uint64(in[1+8:]))
	return cmd, KVCommand{
		Key:   key,
		Value: value,
	}
}

func raftAddressForID(id string, nodes []PeerInfo) string {
	for _, node := range nodes {
		if node.ID == id {
			return node.Address
		}
	}

	return ""
}
